package net.lulihu.common_util.validated;

import lombok.extern.slf4j.Slf4j;
import net.lulihu.AssertKit;
import net.lulihu.ObjectKit.CollectionKit;
import net.lulihu.ObjectKit.StrKit;
import net.lulihu.common_util.validated.annotation.DateStrFormat;
import net.lulihu.common_util.validated.annotation.NumberRange;
import net.lulihu.common_util.validated.annotation.StringRange;
import net.lulihu.dateTime.DateTimeKit;
import net.lulihu.exception.ExceptionEnum;

/**
 * 参数校验工具
 */
@Slf4j
public class ValidatedUtil {

    /**
     * 数值范围
     *
     * @param value            值
     * @param ann              注解对象
     * @param defaultException 不匹配时抛出指定参数异常
     */
    public static void numberRange(Object value, NumberRange ann, ExceptionEnum defaultException) {
        AssertKit.isTrue(
                // 判断是否在指定范围内
                !ParamValidated.isOneExist((Number) value, getNumberRange(value.getClass(), ann)),
                // 不存在 抛出异常
                () -> ParamValidated.throwException(ann.message(), defaultException));
    }


    /**
     * 强制约束字符串取值范围
     *
     * @param value            值
     * @param stringRange      注解对象
     * @param defaultException 不匹配时抛出指定参数异常
     */
    public static void stringRange(Object value, StringRange stringRange, ExceptionEnum defaultException) {
        if (!(value instanceof String))
            throw new IllegalArgumentException(
                    StrKit.format("参数类型不匹配例外:@StringRange注解无法校验{}", value.getClass()));

        String param = (String) value;
        // 验证字符串范围
        String[] range = stringRange.value();
        if (CollectionKit.isNotEmpty(range))
            if (!ParamValidated.isOneExist(param, range))
                ParamValidated.throwException(stringRange.message(), defaultException);

        // 验证字符串最大长度 -1不验证
        int maxLen = stringRange.maxLen();
        if (maxLen != -1)
            if (param.length() > maxLen)
                ParamValidated.throwException(stringRange.message(), defaultException);

        // 验证字符串最小长度 -1不验证
        int minLen = stringRange.minLen();
        if (minLen != -1)
            if (param.length() < minLen)
                ParamValidated.throwException(stringRange.message(), defaultException);
    }

    /**
     * 强制约束字符串时间类型
     *
     * @param value            值
     * @param format           注解对象
     * @param defaultException 不匹配时抛出指定参数异常
     */
    public static void dateStrFormat(String value, DateStrFormat format, ExceptionEnum defaultException) {
        if (StrKit.isEmpty(value)) return;
        try {
            String[] times;
            if (format.plural()) times = value.split(format.pluralSep());
            else times = new String[]{value};
            // 多个时间校验
            for (String time : times) {
                String formatTime = DateTimeKit.format(DateTimeKit.parse(time, format.value()), format.value());
                if (!time.equals(formatTime))
                    ParamValidated.throwException(format.message(), defaultException);
            }
        } catch (Exception e) {
            log.warn("检查时间字段类型例外", e);
            ParamValidated.throwException(format.message(), defaultException);
        }

    }

    /**
     * 获取数值类型范围
     *
     * @param valueClass 注解指定类型
     * @param ann        注解对象
     */
    private static Number[] getNumberRange(Class<?> valueClass, NumberRange ann) {
        if (valueClass.equals(int.class) || valueClass.equals(Integer.class)) {
            return CollectionKit.wrap(ann.INTS());
        }
        if (valueClass.equals(double.class) || valueClass.equals(Double.class)) {
            return CollectionKit.wrap(ann.DOUBLES());
        }
        if (valueClass.equals(long.class) || valueClass.equals(Long.class)) {
            return CollectionKit.wrap(ann.LONGS());
        }
        if (valueClass.equals(short.class) || valueClass.equals(Short.class)) {
            return CollectionKit.wrap(ann.SHORTS());
        }
        if (valueClass.equals(byte.class) || valueClass.equals(Byte.class)) {
            return CollectionKit.wrap(ann.BYTES());
        }
        if (valueClass.equals(float.class) || valueClass.equals(Float.class)) {
            return CollectionKit.wrap(ann.FLOATS());
        }
        throw new IllegalArgumentException("类型不匹配例外");
    }

}
